using Codice.Client.BaseCommands;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.Events;

namespace XLFrame.NodeEditor
{
    /// <summary>
    /// 自定义右键菜单
    /// </summary>
    public class SearchMenuWindowProvider : ScriptableObject, ISearchWindowProvider
    {
        public delegate bool SerchMenuWindowOnSelectEntryDelegate(Type type, Port Tport, SearchTreeEntry searchTreeEntry, SearchWindowContext context);            //声明一个delegate类

        public SerchMenuWindowOnSelectEntryDelegate OnSelectEntryHandler;                              //delegate回调方法

        /// <summary>
        /// 右键菜单树
        /// </summary>
        public MenuTreeData tree = new MenuTreeData("root", null);

        /// <summary>
        /// 右键菜单数据字典
        /// </summary>
        public Dictionary<Type, MenuTreeData> MenuTreeDataDic = new Dictionary<Type, MenuTreeData>();
        /// <summary>
        /// 已处理的类型
        /// </summary>
        private HashSet<Type> processedType = new HashSet<Type>();

        /// <summary>
        /// 选择的端口
        /// </summary>
        private Port m_port = null;

        /// <summary>
        /// 计算菜单数
        /// </summary>
        public class MenuTreeData
        {
            public string Name;
            public Type Type;
            public IMenuWindowData menuWindowData;
            public int Level { get=> GetLevel(); private set=>level = value;}
            private int level = -1;

            public MenuTreeData Parent;
            public Dictionary<string, MenuTreeData> Children = new Dictionary<string, MenuTreeData>();

            public MenuTreeData(string name, IMenuWindowData menuWindowData)
            {
                Name = name;
                if(menuWindowData != null)
                {
                    Type = menuWindowData.GetType();
                    this.menuWindowData = menuWindowData;
                }
            }
            #region 方法
            public int GetLevel()
            {
                if (level <= 0)
                {
                    // 计算深度
                    MenuTreeData menuTreeData = this;
                    int ret = 0;
                    while (menuTreeData != null)
                    {
                        menuTreeData = menuTreeData.Parent;
                        ret++;
                    }
                    level = ret;
                    return level;
                }
                else
                {
                    return level;
                }
            }

            /// <summary>
            /// 添加子节点,名称相同则返回已有的
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public MenuTreeData AddChild(string name, IMenuWindowData type)
            {
                if(Children.ContainsKey(name))
                {
                    return Children[name];
                }
                var child = new MenuTreeData(name, type);
                child.Parent = this;
                Children.Add(name,child);
                return child;
            }

            /// <summary>
            /// 递归获取所有数据
            /// </summary>
            /// <returns></returns>
            public List<MenuTreeData> GetAllData()
            {
                List<MenuTreeData> allData = new List<MenuTreeData>();
                GetAllDataRecursive(this, allData);
                return allData;
            }

            private void GetAllDataRecursive(MenuTreeData menuTreeData, List<MenuTreeData> allData)
            {
                allData.Add(menuTreeData);
                foreach (var child in menuTreeData.Children.Values)
                {
                    GetAllDataRecursive(child, allData);
                }
            }
            #endregion
        }


        public SearchMenuWindowProvider()
        {
            
        }

        /// <summary>
        /// 点击回调
        /// </summary>
        /// <param name="searchTreeEntry"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public bool OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context)
        {
            if (OnSelectEntryHandler == null)
            {
                return false;
            }

            var type = searchTreeEntry.userData as Type;

            return OnSelectEntryHandler(type, m_port,searchTreeEntry, context);
        }

        /// <summary>
        /// 创建菜单样式 每次右键点击都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
        {
            Debug.Log("菜单创建函数");
            var entries = new List<SearchTreeEntry>();

            // 初始化菜单
            var types = GetClassList(typeof(IMenuWindowData));
            foreach (var type in types)
            {
                ParseType(type);
            }


            if (m_port == null)
            {
                entries.Add(new SearchTreeGroupEntry(new GUIContent("创建新节点")));
            }
            else
            {
                entries.Add(new SearchTreeGroupEntry(new GUIContent("创建新节点并连接")));

                // 获取推荐端口,放到最上层没有层级关系
                var iNode = m_port.node as IMenuWindowData;
                var recommend = iNode.GetRecommendedPortNode(m_port.direction == Direction.Input);
                foreach (var item in recommend)
                {
                    if (MenuTreeDataDic.TryGetValue(item, out MenuTreeData value))
                    {
                        entries.Add(new SearchTreeEntry(new GUIContent($"* {value.Name}")) { level = 1, userData = item });
                    }
                }
            }

            CreateSearchTreeEntry(entries);
            return entries;
        }

        /// <summary>
        /// 通过tree创建List<SearchTreeEntry>内容 用于创建菜单样式
        /// </summary>
        private void CreateSearchTreeEntry(List<SearchTreeEntry> entries)
        {
            var data = tree.GetAllData();

            if(m_port == null)
            {
                foreach (var x in data)
                {
                    if (x.Parent == null)
                        continue;
                    if (x.Children.Count == 0)  // 添加一个节点
                        entries.Add(new SearchTreeEntry(new GUIContent(x.Name)) { level = x.Level - 1, userData = x.Type });
                    else                        // 添加一个组
                        entries.Add(new SearchTreeGroupEntry(new GUIContent(x.Name)) { level = x.Level - 1 });
                }
            }
            else
            {
                foreach (var x in data)
                {
                    if (x.Parent == null)
                        continue;

                    // 这里筛选哪些不需要显示 拉起的端口不为空,在这个类中找不到推荐端口就跳过此菜单
                    if (x.menuWindowData != null && x.menuWindowData.ConnectRecommendedPort(m_port) == null)
                        continue;

                    if (x.Children.Count == 0)  // 添加一个节点
                        entries.Add(new SearchTreeEntry(new GUIContent(x.Name)) { level = x.Level - 1, userData = x.Type });
                    else
                        entries.Add(new SearchTreeGroupEntry(new GUIContent(x.Name)) { level = x.Level - 1 });
                }

                // 优化菜单显示 到此返回的数组中包含了所有的组和元素(包括空的组)

                List<SearchTreeEntry> tempEntries = new List<SearchTreeEntry>();
                List<SearchTreeEntry> tempRemoveEntries = new List<SearchTreeEntry>();

                // 循环便利entries检查相邻组是否为一级别,如果是则删除
                for (int i = 1; i < entries.Count; i++)
                {
                    if (entries[i].GetType() == typeof(SearchTreeEntry))
                    {
                        // 当前元素属于上一个组
                        if(tempEntries.Count >= 1 && tempEntries[tempEntries.Count-1].level == entries[i].level - 1)
                        {
                            // 正常添加,表明路径正常有元素
                            tempEntries.Clear();
                        }
                        else if (tempEntries.Count >= 1 && tempEntries[tempEntries.Count - 1].level == entries[i].level)
                        {
                            // 上一个组没有元素,但此元素和上组为同一个父级,删除上一个组,不删除他父级
                            tempRemoveEntries.Add(tempEntries[tempEntries.Count - 1]);
                            tempEntries.RemoveAt(tempEntries.Count - 1);
                            tempEntries.Clear();
                        }
                        // 当前元素既不属于上一个组,也不属于上一个组的父级 不应该进入啊?
                        else
                        {
                            // 删除上一个组
                            tempRemoveEntries.AddRange(tempEntries);
                            tempEntries.Clear();
                        }
                    }

                    if(entries[i] is SearchTreeGroupEntry)
                    {
                        if(tempEntries.Count == 0)
                        {
                            // 默认添加一个组
                            tempEntries.Add(entries[i]);
                        }
                        // 当前组的level比上一个组的level大,说明是子组
                        else if (tempEntries.Count >= 1 && tempEntries[tempEntries.Count - 1].level < entries[i].level)
                        {
                            // 加入缓存
                            tempEntries.Add(entries[i]);
                        }
                        // 当前组的level和上一个组的level相同,说明是同级组
                        else if(tempEntries.Count >= 1 && tempEntries[tempEntries.Count - 1].level == entries[i].level)
                        {
                            // 删除上个同级组,不先保留父级 不确定往下是否还有同级组或者子元素
                            tempRemoveEntries.Add(tempEntries[tempEntries.Count-1]);
                            tempEntries.RemoveAt(tempEntries.Count - 1);
                            tempEntries.Add(entries[i]);
                        }
                        // 既不是子组也不是同级组,说明是父组,但没有被元素填充
                        else
                        {
                            // 删除上一个组
                            tempRemoveEntries.AddRange(tempEntries);
                            tempEntries.Clear();
                            tempEntries.Add(entries[i]);
                        }
                    }
                }

                // tempEntries没有被清空,说明最后一个组没有被填充
                tempRemoveEntries.AddRange(tempEntries);
                tempEntries.Clear();

                foreach (var x in tempRemoveEntries)
                {
                    entries.Remove(x);
                }
            }
        }

        /// <summary>
        /// 打开菜单 后续增加参数
        /// </summary>
        public void Open(Vector2 screenMousePosition,Port port = null)
        {
            // port 是起始端口的信息,有可能是input或者output
            if (port != null)
            {
                // 重新显示搜索菜单
                // 根据port的类型显示不同的菜单
                m_port = port;
            }
            else
            {
                m_port = null;
            }
            SearchWindow.Open(new SearchWindowContext(screenMousePosition), this);
        }

        /// <summary>
        /// 解析一种类型到菜单树 缓存数据
        /// </summary>
        /// <returns></returns>
        private void ParseType(Type type)
        {
            if(processedType.Contains(type))
            {
                return;
            }
            else
            {
                processedType.Add(type);
            }


            var path = GetMenuPathFromType(type);
            if(string.IsNullOrEmpty(path.MenuPath))
            {
                Debug.LogWarning(type.Name + "未设置MenuPath属性");
                return;
            }

            var pathArray = path.MenuPath.Split('/');
            MenuTreeData selete = tree;
            for (int i = 0; i < pathArray.Length-1; i++)
            {
                selete = selete.AddChild(pathArray[i], null);
            }
            selete = selete.AddChild(pathArray[pathArray.Length -1], path);
            MenuTreeDataDic.TryAdd(type, selete);

            return;
        }


        /// <summary>
        /// 获取并返回一个特定基类或接口的所有非抽象、非泛型实现类的Type列表
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private List<Type> GetClassList(Type type)
        {
            var q = type.Assembly.GetTypes() // 从type所在的程序集中获取所有类型
                    .Where(x => !x.IsAbstract) // 筛选出非抽象类，因为抽象类不能被实例化
                    .Where(x => !x.IsGenericTypeDefinition) // 筛选出非泛型定义类，因为泛型定义本身不能直接被实例化
                    .Where(x => type.IsAssignableFrom(x)); // 筛选出所有可以被赋值给type的类型，即所有继承自type或实现了type接口的类

            return q.ToList(); // 将筛选结果转换为List<Type>并返回
        }


        /// <summary>
        /// 获取指定类型的MenuPath属性值
        /// </summary>
        /// <param name="type">要获取MenuPath的类型</param>
        /// <returns>MenuPath的值，如果未找到则返回null</returns>
        private IMenuWindowData GetMenuPathFromType(Type type)
        {
            // 确保type不为null且继承自NodeViewBase
            if (type != null && typeof(IMenuWindowData).IsAssignableFrom(type))
            {
                // 创建type的实例
                object instance = Activator.CreateInstance(type);
                if (instance != null && instance is IMenuWindowData node)
                {
                    // 获取MenuPath属性的值
                    node.InitData();
                    return node;
                }
            }

            return null;
        }
    }
}